// 为了学习目的，2025年5月8日到9日我在原有基础上修改了原来的代码，变成十进制数转十六进制数及反向变换的代码
// Fu Huizhong <fuhuizn@163.com>
/*
 * SPDX-FileCopyrightText: 2021~2021 CSSlayer <wengxt@gmail.com>
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */
#include "netinput.h"
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/utf8.h>
#include <fcitx/candidatelist.h>
#include <fcitx/inputpanel.h>
#include <fcitx/instance.h>
#include <fcitx/userinterfacemanager.h>
#include <punctuation_public.h>
#include <quickphrase_public.h>
#include <utility>
#include "libconvert.h"

namespace {

// Template to help resolve iconv parameter issue on BSD.
template <class T>
struct function_traits;

// partial specialization for function pointer
template <class R, class... Args>
struct function_traits<R (*)(Args...)> {
    using result_type = R;
    using argument_types = std::tuple<Args...>;
};

template <class T>
using second_argument_type = typename std::tuple_element<
    1, typename function_traits<T>::argument_types>::type;

static const std::array<fcitx::Key, 10> selectionKeys = {
    fcitx::Key{FcitxKey_1}, fcitx::Key{FcitxKey_2}, fcitx::Key{FcitxKey_3},
    fcitx::Key{FcitxKey_4}, fcitx::Key{FcitxKey_5}, fcitx::Key{FcitxKey_6},
    fcitx::Key{FcitxKey_7}, fcitx::Key{FcitxKey_8}, fcitx::Key{FcitxKey_9},
    fcitx::Key{FcitxKey_0},
};

class NetIMCandidateWord : public fcitx::CandidateWord {
public:
    NetIMCandidateWord(NetIMEngine *engine, std::string text)
        : engine_(engine) {
        setText(fcitx::Text(std::move(text)));
    }

    void select(fcitx::InputContext *inputContext) const override {
        inputContext->commitString(text().toString());
        auto state = inputContext->propertyFor(engine_->factory());
        state->reset();
    }

private:
    NetIMEngine *engine_;
};

class NetIMCandidateList : public fcitx::CandidateList,
                           public fcitx::PageableCandidateList,
                           public fcitx::CursorMovableCandidateList {
public:
    NetIMCandidateList(NetIMEngine *engine, fcitx::InputContext *ic,
                       const std::string &code)
        : engine_(engine), ic_(ic), code_(std::stoi(code)) {
        setPageable(this);
        setCursorMovable(this);
        //auto state = ic_->propertyFor(engine_->factory());
        //for (int i = 0; i < 4; i++) {
            //labels_[i].clear();
            //labels_[i].append(state->res[i]);
        //}
        labels_[0].clear();
        labels_[1].clear();
        //labels_[0].append("注：");
        generate();
    }

    const fcitx::Text &label(int idx) const override { return labels_[idx]; }

    const fcitx::CandidateWord &candidate(int idx) const override {
        return *candidates_[idx];
    }
    int size() const override { return 2; }
    fcitx::CandidateLayoutHint layoutHint() const override {
        return fcitx::CandidateLayoutHint::NotSet;
    }
    bool usedNextBefore() const override { return false; }
    void prev() override {
        if (!hasPrev()) {
            return;
        }
        --code_;
        auto state = ic_->propertyFor(engine_->factory());
        state->setCode(code_);
    }
    void next() override {
        if (!hasNext()) {
            return;
        }
        code_++;
        auto state = ic_->propertyFor(engine_->factory());
        state->setCode(code_);
    }

    bool hasPrev() const override { return code_ > 0; }

    bool hasNext() const override { return code_ < 1; }

    void prevCandidate() override { cursor_ = (cursor_ + 1) % 2; }

    void nextCandidate() override { cursor_ = (cursor_ + 1) % 2; }

    int cursorIndex() const override { return cursor_; }

private:
    void generate() {
        auto state = ic_->propertyFor(engine_->factory());
        candidates_[0] = std::make_unique<NetIMCandidateWord>(engine_, state->candStr1);
        candidates_[1] = std::make_unique<NetIMCandidateWord>(engine_, state->candStr2);

    }

    NetIMEngine *engine_;
    fcitx::InputContext *ic_;
    fcitx::Text labels_[2];
    std::unique_ptr<NetIMCandidateWord> candidates_[2];
    int code_;
    int cursor_ = 0;
};

} // namespace

std::string translate(fcitx::KeySym c)
{
    switch (c)
    {
    case '.':
        return "。";
        break;
    case ',':
        return "，";
        break;
    case '?':
        return "？";
        break;
    case '!':
        return "！";
        break;
    case ';':
        return "；";
        break;
    
    default:
        break;
    }
    return "";
}

void NetIMState::keyEvent(fcitx::KeyEvent &event) {
    NetIMEngine::net_imstat = this;
    if (event.key().check(FcitxKey_Control_R)) {
        int status = IMGetStatus();
        if(status==1) {
            NetIMEngine::net_ic = event.inputContext();
            IMEndInput();
            IMShiftStatus();
            //wait_status = false;
            // char *s = IMNetRead();
            // if (s!=NULL)
            // {
            //     //FCITX_INFO() << "commitString\n";
            //     ic_->commitString(s);
            //     free(s);
            // }
        }
        else if(status==0)
        {
            IMBeginInput();
            IMShiftStatus();
            
            //wait_status = true; 
        }

        updateUI();
        return event.filterAndAccept();
    }

    std::string ts = translate(event.key().sym());
    if (!ts.empty()) 
    {
        ic_->commitString(ts);
        updateUI();
        return event.filterAndAccept();
    }
    
    event.setForward(true);
    event.forward();
    
    updateUI();
    return;
}

void NetIMState::setCode(int code) {
    if (code < 0 || code > 999) {
        return;
    }
    buffer_.clear();
    auto codeStr = std::to_string(code);
    buffer_.type(std::to_string(code));
    updateUI();
}

void NetIMState::updateUI() {
    auto &inputPanel = ic_->inputPanel();
    inputPanel.reset();

    // if(wait_status) {
    //     inputPanel.setCandidateList(std::make_unique<NetIMCandidateList>(
    //         engine_, ic_, std::string("0")));
    // }
    switch ( (int)IMGetStatus() ) {
        case 0:
        {
            fcitx::Text preedit1(std::string("按右侧Ctrl开始录音"));
            inputPanel.setPreedit(preedit1);
        }
            
            break;
        case 1:
        {
            fcitx::Text preedit2(std::string("按右侧Ctrl结束录音"),
                                fcitx::TextFormatFlag::HighLight);
            inputPanel.setClientPreedit(preedit2);
        }
            
            break;
        case 2:
        {
            fcitx::Text preedit3(std::string("识别中..."));
            inputPanel.setPreedit(preedit3);
        }
            
            break;
    }
    // if (IMGetStatus()==1) {
    //     fcitx::Text preedit(std::string("按右侧Ctrl结束录音"),
    //                         fcitx::TextFormatFlag::HighLight);
    //     inputPanel.setClientPreedit(preedit);
    // } 
    // else if(IMGetStatus==0)
    // {
    //     fcitx::Text preedit(std::string("按右侧Ctrl开始录音"));
    //     inputPanel.setPreedit(preedit);
    // }

    ic_->updateUserInterface(fcitx::UserInterfaceComponent::InputPanel);
    ic_->updatePreedit();
}

NetIMEngine::NetIMEngine(fcitx::Instance *instance)
    : instance_(instance), factory_([this](fcitx::InputContext &ic) {
          return new NetIMState(this, &ic);
      }) {
    conv_ = iconv_open("UTF-8", "GB18030");
    if (conv_ == reinterpret_cast<iconv_t>(-1)) {
        throw std::runtime_error("Failed to create converter");
    }
    instance->inputContextManager().registerProperty("NetIMState", &factory_);
}

void NetIMEngine::activate(const fcitx::InputMethodEntry &entry,
                           fcitx::InputContextEvent &event) {
    FCITX_UNUSED(entry);
    auto *inputContext = event.inputContext();
    net_ic = inputContext;
    // Request full width.
    fullwidth();
    chttrans();
    for (const auto *actionName : {"chttrans", "punctuation", "fullwidth"}) {
        if (auto *action =
                instance_->userInterfaceManager().lookupAction(actionName)) {
            inputContext->statusArea().addAction(
                fcitx::StatusGroup::InputMethod, action);
        }
    }
    IMResetStatus();
    if(!looper_status){
        looper_status = true;
        
        looper = new std::thread(NetIMEngine::net_read_loop);
    }
    
}

void NetIMEngine::net_read_loop() {
    
    while(true){
        char *s = IMNetRead();
        if (s!=NULL && net_ic !=NULL) {
            fcitx::InputContext *ic = net_ic;
            if (ic!=NULL) {
                ic->commitString(s);
                IMShiftStatus();
                if(net_imstat!=NULL)
                    net_imstat->updateUI();
            }
            
            //FCITX_INFO() << s;
            free(s);
        }
        
    }
}

void NetIMEngine::keyEvent(const fcitx::InputMethodEntry &entry,
                           fcitx::KeyEvent &keyEvent) {
    FCITX_UNUSED(entry);
    if (keyEvent.isRelease() || keyEvent.key().states()) {
        return;
    }
    //FCITX_INFO() << keyEvent.key() << " isRelease=" << keyEvent.isRelease();
    auto ic = keyEvent.inputContext();
    auto *state = ic->propertyFor(&factory_);
    state->keyEvent(keyEvent);
}

void NetIMEngine::reset(const fcitx::InputMethodEntry &,
                        fcitx::InputContextEvent &event) {
    auto *state = event.inputContext()->propertyFor(&factory_);
    state->reset();
}

FCITX_ADDON_FACTORY(NetIMEngineFactory);
